﻿/**
 * lineChart
 * Charts Collection
 *
 * @author		Duarte Peixinho, mail: duarte.peixinho@gmail.com
 * @version		1.0
 */

package com.duartepeixinho.charts.chartsType
{
	import com.duartepeixinho.charts.grid.ChartGrid
	import flash.display.Shape;
	import flash.events.Event;
	import flash.filters.BlurFilter;
	import flash.filters.DropShadowFilter;
	import flash.geom.Point;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import com.duartepeixinho.ptween.Ptween;
	
	public class LineChart extends ChartGrid
	{
		//const
		private const LINE_WIDTH:Number = 1.5;
		
		//vars
		private var _values:Array;
		private var _animation:Boolean;
		private var _labels:Array = new Array();
		private var _shapes:Array = new Array();
		private var _tweenShape:Array = new Array();
		private var _dropShadow:Boolean;
		
		/**
		 * Creates a Multi Line Chart.
		 * 
		 * @param		values			Array		Schema of the array: [ values:Array = [ x:Number, y:Number ], lineWidth:uint, color:uint, label:String ]
		 * @param		animation		Boolean		Use animation on the chart (Ptween)
		 * @param		dropShadow		Boolean		Use dropShadow on the lines
		 * @param		coordEnd		Point		Point of the width and heigth if the axis
		 * @param		CountInit		Point		Point that determines the starting number of each axis
 		 * @param		CountEnd		Point		How many numbers in each axis
		 * @param		xCount			Number		Increase Number of the XX axis
		 * @param		yCount			Number		Increase Number of the YY axis
		 * @param		showXMarks		Boolean		Show Labels of the XX axis
		 * @param		showYMarks		Boolean		Show Labels of the YY axis
		 * @param		xLabel			String		String to appear as the label of the XX axis
		 * @param		yLabel			String		String to appear as the label of the YY axis
		 * @param		grid			Boolean		Show the background grid or not
		 * @param		showZero		Boolean		Show the 0 on the corner or not
		 * @param		title			String		Title of the chart
		 */
		
		public function LineChart(values:Array, animation:Boolean,dropShadow:Boolean ,coordEnd:Point, CountInit:Point, CountEnd:Point, xCount:Number, yCount:Number, showXMarks:Boolean, showYMarks:Boolean, xLabel:String = null, yLabel:String = null, grid:Boolean = true, showZero:Boolean = false, title:String = null )
		{		
			//instantiates the parent constructor
			super(coordEnd, CountInit, CountEnd, xCount, yCount, showXMarks, showYMarks, xLabel, yLabel, grid, showZero, title);
			_values = values;
			_animation = animation;
			_dropShadow = dropShadow;
			
			//draw the lines in the chart			
			buildLines();
		}		
		
		//draw Lines
		private function buildLines():void {		
			
			//getting colors automatically
			var colorsPallette:Number = 10777215;
			//convert dec to hex: (16777215).toString(16);
			
			//sets the counter
			var i:int;
			var j:int;
			
			//loop to get/set the color
			for (i = 0; i < _values.length; i++) {
				if (_values[i][2].length == 0) {
					//sets the color
					_values[i][2] = "0x" + (colorsPallette / _values.length * (i+1)).toString(16);
				}
				//creates the label
				_labels[i] = new TextField();
				_labels[i].text = _values[i][3];
				_labels[i].height = _labels[i].textHeight + 5;
				_labels[i].setTextFormat(new TextFormat(null, 9, _values[i][2]));		
				if (_dropShadow) _labels[i].filters = [new DropShadowFilter(4,45,0,0.5)];
				addChild(_labels[i]);
					
			}					
			
			var pointColor:uint;
			
			//non animated
			if (!_animation) {
				for (i = 0; i < _values.length; i++) {
					pointColor = _values[i][2];
					_shapes[i] = new Shape();
					if (_dropShadow) _shapes[i].filters = [new DropShadowFilter()];
					if (_values[i][1]) {
						_shapes[i].graphics.lineStyle(_values[i][1], pointColor);
					}
					else {
						_shapes[i].graphics.lineStyle(LINE_WIDTH, pointColor);
					}
					_shapes[i].graphics.moveTo(getValue(i,0).x, getValue(i,0).y);
					for (j = 1; j < _values[i][0].length; j++) {
						_shapes[i].graphics.lineTo(getValue(i, j).x, getValue(i, j).y);
						_labels[i].x = getValue(i, j).x + 5;
						_labels[i].y = getValue(i, j).y - 10;
					}		
					addChild(_shapes[i]);
				}
			}
			
			//animated
			else if (_animation) {
				addEventListener(Event.ENTER_FRAME, loop);
				for (i = 0; i < _values.length; i++) {
					pointColor = _values[i][2];				
					_shapes[i] = new Shape();
					if (_values[i][1]) {
						_shapes[i].graphics.lineStyle(_values[i][1], pointColor);
					}
					else {
						_shapes[i].graphics.lineStyle(LINE_WIDTH, pointColor);
					}
					_shapes[i].graphics.moveTo(getValue(i, 0).x, getValue(i, 0).y);
					_tweenShape[i] = new Shape();					
					if (_dropShadow) _shapes[i].filters = [new DropShadowFilter(), new BlurFilter(2, 2, 2)];
					else _shapes[i].filters = [new BlurFilter(2, 2, 2)];
					addChild(_shapes[i]);
					_tweenShape[i].x = getValue(i, 0).x;
					_tweenShape[i].y = getValue(i, 0).y;
					
					Ptween.addTween(_tweenShape[i], { x:getValue(i, 1).x, y:getValue(i, 1).y, time:2, onComplete:drawLineAnimated, onCompleteParams:[i,2], transition:"easeOutSine" } );				
				}
			}			
		}
		
		/*
		 * Function to draw lines on Enter Frame when animation is activated
		 */ 
		private function loop(e:Event):void {
			for (var i:int = 0; i < _values.length; i++) {
				_shapes[i].graphics.lineTo(_tweenShape[i].x, _tweenShape[i].y);
				_labels[i].x = _tweenShape[i].x;
				_labels[i].y = _tweenShape[i].y -10;
			}
		}
		
		/*
		 * Recursive function to create the tweens
		 */ 
		private function drawLineAnimated(array1:String, count1:String):void {
			var array:int = int(array1);
			var count:int = int(count1);

			if (Boolean(_values[array][0][count])) {				
				Ptween.addTween(_tweenShape[array], { x:getValue(array, count).x, y:getValue(array, count).y, time:2, onComplete:drawLineAnimated, onCompleteParams:[array,count +1], transition:"easeOutSine" } );				
			}
		}
		
		/**
		 * Creates a Multi Line Chart.
		 * 
		 * @param		array			Number		Wich array position to get its valyue
		 * @param		count			Number		Get the number to return the array value
		 * @return						Point		Returns the poisiton point
		 */ 

		private function getValue(array:uint, count:Number):Point {
			
			var subValues:Array = _values[array][0];							
			return new Point(convertCoordChart(new Point(subValues[count][0], subValues[count][1])).x, convertCoordChart(new Point(subValues[count][0], subValues[count][1])).y);
		}
	}
}